<!--
 * @Author: liyin 2179253556@qq.com
 * @Date: 2023-03-20 13:51:35
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2024-07-02 08:24:47
 * @FilePath: Index.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
    <div class="user-info-box">
        <SearchComp @clear="clearHandle">
            <RowItem label="关键字" :count="1">
                <el-input clearable placeholder="请输入用户昵称关键字搜索" v-model="personQuery.key_word" prefix-icon="Search"
                    @input="search" style="width: 100%">
                </el-input>
            </RowItem>
            <RowItem label="选择状态" :count="2">
                <el-select v-model="personQuery.status" @change="search" style="width:100%;" clearable
                    placeholder="请选择状态">
                    <el-option label="有效" value="1"></el-option>
                    <el-option label="无效" value="0"></el-option>
                </el-select>
            </RowItem>
            <RowItem label="选择角色" :count="3">
                <el-cascader placeholder="请选择角色" @change="search" style="width:100%;" v-model="role_ids"
                    :options="roleList" :props="{
            checkStrictly: true,
            label: 'role_name',
            value: 'id'
        }" clearable></el-cascader>
            </RowItem>
        </SearchComp>
        <Table :data="tableData" :config="tableConfig" @handleEdit="handleEdit" :showLoading="loading" :total="total"
            @sizeChange="sizeChange" @CurrentChange="CurrentChange">
            <el-button type="primary" @click="Add">添加账号</el-button>
        </Table>
        <!-- 添加权限弹窗 -->
        <Model :title="addForm.id ? '编辑账号' : '添加账号'" :modelShow="dialogVisible" width="780px"
            @cancel="resetForm(addFormRef)" @confirm="submitForm(addFormRef)">
            <el-form label-width="80px" size="default" :rules="rules" :model="addForm" ref="addFormRef">
                <el-row :gutter="20">
                    <el-col :span="24">
                        <el-form-item label="用户名称" prop="account">
                            <el-input v-model="addForm.account" placeholder="请输入账号名称"></el-input>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24">
                        <el-form-item label="用户昵称" prop="name">
                            <el-input v-model="addForm.name" placeholder="请输入账号昵称"></el-input>
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row :gutter="20">
                    <el-col :span="24">
                        <el-form-item label="密码" prop="passwd" :required="!addForm.id">
                            <el-input type="password" v-model="addForm.passwd" :readonly="readonlyFlag"
                                autocomplete='off' @focus="handlerIpClick" show-password
                                placeholder="8-20位数字,大小写字母特殊符号组合密码">
                            </el-input>
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row :gutter="20">
                    <el-col :span="24">
                        <el-form-item label="确认密码" prop="passwd2" :required="!addForm.id">
                            <el-input type="password" v-model="addForm.passwd2" :readonly="readonlyFlag"
                                autocomplete='off' @focus="handlerIpClick" show-password placeholder="请再次输入密码">
                            </el-input>
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row :gutter="20">
                    <el-col :span="12">
                        <el-form-item label="角色权限" prop="role_id">
                            <el-cascader placeholder="请选择角色权限" v-model="addForm.role_id" :options="roleList" :props="{
            checkStrictly: true,
            label: 'role_name',
            value: 'id'
        }" clearable></el-cascader>
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="状态" prop="status">
                            <el-radio-group v-model="addForm.status">
                                <el-radio-button label="1">有效</el-radio-button>
                                <el-radio-button label="0">无效</el-radio-button>
                            </el-radio-group>
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row :gutter="20">
                    <el-col :span="24">
                        <el-form-item label="失效时间" prop="expire_time">
                            <el-date-picker v-model="addForm.expire_time" type="datetime" placeholder="请选择失效时间"
                                align="center" value-format="YYYY-MM-DD HH:mm:ss" style="width:100%"></el-date-picker>
                        </el-form-item>
                    </el-col>
                    <el-col :span="24">
                        <el-form-item label="上传头像" prop="inch">
                            <div class="uploadList">
                                <div style="display: inline-block;height: 72px;">
                                    <el-upload class="avatar-uploader" :show-file-list="false"
                                        :on-success="handleAvatarSuccess" :http-request="uploadAvatorAdd"
                                        :before-upload="beforeAvatarUpload">
                                        <el-image v-if="addForm.inch" :src="addForm.inch" fit="cover"
                                            style="width: 100%;height: 100%;"></el-image>
                                        <el-icon v-if="!addForm.inch" class="avatar-uploader-icon">
                                            <Plus />
                                        </el-icon>
                                        <div v-if="!addForm.inch">上传头像</div>
                                    </el-upload>
                                </div>
                            </div>
                        </el-form-item>
                    </el-col>
                </el-row>
            </el-form>
        </Model>
    </div>
</template>
<script setup lang="ts">
import { UploadProps, UploadRequestOptions } from 'element-plus'
import * as imageConversion from 'image-conversion'; // 图片压缩
import upload from '../../util/OSSUpload'
import $util from '../../util/util'
import { ref, h, onMounted, reactive, nextTick, watch } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import { PiniaStore } from '../../store'
import { getUserList, deleteUser, createUser, updateUser, getRole } from '../Api/index'
import Md5 from 'js-md5'
import Base64 from '../../util/Base64'
const store = PiniaStore()
const validatePass = (rule: any, value: any, callback: any) => {
    if (!addForm.id && value === '') {
        callback(new Error('请输入密码'))
    } else if (addForm.id && !addForm.passwd && addForm.passwd2) {
        callback(new Error('请输入密码'))
    } else if (value !== '' && !/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[._~!@#$^&*])[A-Za-z0-9._~!@#$^&*]{8,20}$/g.test(value)) {
        callback(new Error('请输入包含英文字母大小写、数字和特殊符号的 8-20 位组合密码'))
    } else {
        callback()
    }
}
const validatePass2 = (rule: any, value: any, callback: any) => {
    if (!addForm.id && value === '') {
        callback(new Error('请再次输入密码'))
    } else if (value !== addForm.passwd) {
        callback(new Error('两次输入密码不一致!'))
    } else {
        callback()
    }
}
// 手机号验证
const validatePhone = (rule: any, value: any, callback: any) => {
    if (value === "") {
        callback(new Error("请输入手机号"));
    } else {
        if (!/^1[3456789]\d{9}$/.test(value)) {
            callback(new Error("请输入正确的手机号"));
        } else {
            callback();
        }
    }
}
const loading = ref(false)
const personQuery = reactive({
    key_word: '',
    status: '',
    page: 1,
    page_size: store.pageQuery.page_size,
})
const role_ids = ref<any>([])
const readonlyFlag = ref(true)
const handlerIpClick = () => {
    readonlyFlag.value = false
}
const dialogVisible = ref(false)
const addFormRef = ref<FormInstance>()
const addForm = reactive({
    id: '',
    account: '',
    passwd: '',
    passwd2: '',
    expire_time: '',
    role_id: [],
    name: '',
    //状态 1-有效 0-无效
    status: '1',
    inch: '',
})
const rules = reactive<FormRules>({
    account: [{ required: true, message: '请输入账号名称', trigger: 'blur' }],
    name: [{ required: true, message: '请输入账号昵称', trigger: 'blur' }],
    passwd: [{ required: true, validator: validatePass, trigger: 'blur' }],
    passwd2: [{ required: true, validator: validatePass2, trigger: 'blur' }],
    role_id: [{ required: true, message: '请选择角色权限', trigger: 'blur' }],
    expire_time: [{ required: true, message: '请选择失效时间', trigger: 'blur' }],
    school_ids: [{ required: true, message: '请选择所管学校', trigger: 'blur' }],
})
// 点击清空条件触发
const clearHandle = () => {
    personQuery.key_word = ''
    personQuery.status = ''
    role_ids.value = []
    personQuery.page = 1
    getList()
}
// 表格数据
const total = ref(0)
const tableData = ref([])
const tableConfig = ref([
    { name: 'index', label: '序号', width: '60', type: 'index', checked: true },
    { name: 'account', label: '用户名称', type: 'change', width: '', checked: true },
    { name: 'name', label: '用户昵称', type: 'change', width: '', checked: true },
    // { name: 'role_name', label: '角色权限', type: 'change', width: '', checked: true },

    {
        name: 'status',
        label: '账号状态',
        width: '',
        checked: true,
        type: 'status',
        formatter: [
            { name: 0, label: '无效', status: 'danger' },
            { name: 1, label: '有效', status: 'success' }
        ]
    },
    { name: 'creator_name', label: '创建人', type: 'change', width: '', checked: true },
    { name: 'create_time', label: '创建时间', type: 'change', width: '', checked: true },
    { name: 'expire_time', label: '过期时间', type: 'change', width: '', checked: true },
    { name: 'update_time', label: '更新时间', type: 'change', width: '', checked: true },
    {
        name: '',
        label: '操作',
        width: '120',
        type: 'edit',
        checked: true,
        formatter: [
            { name: 'Edit', label: '编辑', font: true, link: true },
            { name: 'Delete', label: '删除', font: true, link: true }
        ]
    }
])
// 点击搜索按钮
const search = $util.debounce((val: string | number) => {
    personQuery.page = 1
    getList()
}, 500)
// 获取用户列表
const getList = async () => {
    loading.value = true
    console.log(role_ids.value)
    const params = {
        ...personQuery,
        role_id: role_ids.value!=null&&role_ids.value.length > 0 ? role_ids.value[role_ids.value.length - 1] : ''
    }
    const res: any = await getUserList(params)
    if (res.code !== 1) {
        loading.value = false
        return ElMessage.error(res.message)
    }
    tableData.value = res.data
    total.value = res.total
    loading.value = false
}
// 点击添加用户
const Add = async () => {
    addForm.id = ''
    dialogVisible.value = true
}
const submitForm = async (formEl: FormInstance | undefined) => {
    if (!formEl) return
    formEl.validate(async (valid: any) => {
        if (valid) {
            const base64 = new Base64()
            let obj: any = {
                account: addForm.account,
                passwd: addForm.passwd ? Md5(addForm.passwd) : '',
                passwd2: addForm.passwd2 ? Md5(addForm.passwd2) : '',
                expire_time: addForm.expire_time,
                role_id: addForm.role_id.length > 0 ? addForm.role_id[addForm.role_id.length - 1] : '',
                name: addForm.name,
                status: addForm.status,
                inch: addForm.inch
            }
            if (addForm.id) {
                obj.id = addForm.id
            }
            const res: any = addForm.id ? await updateUser(obj) : await createUser(obj)
            if (res.code !== 1) return ElMessage.error(res.message)
            ElMessage.success(res.message)
            dialogVisible.value = false
            getList()
            formEl.resetFields()
            reset()
        } else {
            console.log('error submit!')
        }
    })
}
const resetForm = (formEl: FormInstance | undefined) => {
    if (!formEl) return
    dialogVisible.value = false
    formEl.resetFields()
    reset()
}
const reset = () => {
    addForm.id = ''
    addForm.account = ''
    addForm.passwd = ''
    addForm.passwd2 = ''
    addForm.expire_time = ''
    addForm.role_id = []
    addForm.name = ''
    addForm.status = '1'
    addForm.inch = ''
}
// 点击设置菜单权限
const handleEdit = (item: any, name: string) => {
    if (name === 'Edit') {
        nextTick(() => {
            addForm.id = item.id
            addForm.account = item.account
            addForm.expire_time = item.expire_time
            // 查找角色父级id
            const str: any = []
            const arr = $util.getAllParentArr(roleList.value, item.role_id)
            arr.reverse().forEach((k: any) => {
                str.push(k.id)
            })
            addForm.role_id = str
            addForm.name = item.name
            addForm.status = item.status
            addForm.inch = item.inch
        })
        dialogVisible.value = true
    } else if (name === 'Delete') {
        ElMessageBox({
            title: '温馨提示',
            message: h('p', { style: 'font-weight:bold;font-size: 15px;color: #333333;' }, [
                h('span', null, '您确定要删除该账号吗？'),
                h('p', { style: 'font-size: 14px;font-weight:normal;color: rgba(0,0,0,0.65);margin-top:10px;' }, '删除后将无法恢复，确定要继续吗?'),
            ]),
            showCancelButton: true,
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning',
            beforeClose: async (action, instance, done) => {
                if (action === 'confirm') {
                    console.log(item.id)
                    const res: any = await deleteUser({ id: item.id })
                    if (res.code !== 1) {
                        done()
                        return ElMessage.error(res.message)
                    }
                    ElMessage.success(res.message)
                    getList()
                    done()
                } else {
                    done()
                }
            },
        }).then((action) => {
        })
    } else {
        // 其他可自行添加
    }
}
// 点击翻页器的长度
const sizeChange = () => {
    personQuery.page_size = store.pageQuery.page_size
    getList()
}
// 点击翻页器的页码
const CurrentChange = () => {
    personQuery.page = store.pageQuery.page
    getList()
}
// 获取角色列表
const roleList = ref<any>()
const getRoleList = async () => {
    const res: any = await getRole()
    if (res.code !== 1) return ElMessage.error(res.message)
    roleList.value = res.data
}
// 上传头像
// 上传图片
const beforeAvatarUpload: UploadProps['beforeUpload'] = rawFile => {
    const typeList = ['image/jpeg', 'image/png']
    const isTypeValid = typeList.includes(rawFile.type)
    // const isLt2M = rawFile.size / 1024 / 1024 < 2
    if (!isTypeValid) {
        ElMessage.error('请上传正确的图片!')
        return false
    }
    // if (!isLt2M) {
    //     Message.error('上传图片大小不能超过2M!')
    //     return false
    // }
    const params: any = { size: 200, type: 'image/jpeg' }
    return new Promise(async (resolve, reject) => {
        if (rawFile.size / 1024 > 300) { // 大于 300 kb 就压缩
            let file: any = await pngToWhiteBg(rawFile)
            const fileOfBlob = new File([file], `${new Date().getTime()}.png`, { type: file.type })
            imageConversion.compressAccurately(fileOfBlob, 250).then(res => {
                console.log(res)
                resolve(res)
            })
        } else if (isTypeValid) {
            // 无需压缩直接返回原文件
            resolve(rawFile)
        } else {
            reject()
        }
    })
}
const pngToWhiteBg = async (file: any) => {
    let read = new FileReader();
    read.readAsDataURL(file); // 文件转base64
    return new Promise((resolve, reject) => {
        read.onload = (e: any) => {
            let img: any = new Image();
            img.src = e.target.result;
            img.onload = async () => {
                // 生成canvas
                let canvas = document.createElement("canvas");
                let context: any = canvas.getContext("2d");
                // 绘制图片到canvas上
                canvas.width = img.width;
                canvas.height = img.height;

                // 在canvas绘制前填充白色背景
                context.fillStyle = "#fff";
                context.fillRect(0, 0, canvas.width, canvas.height);
                context.drawImage(img, 0, 0);
                let base64 = canvas.toDataURL(file["type"], 1);
                let newFile = dataUrlToFile(base64);
                resolve(newFile);
            }
        }
    })
}
const dataUrlToFile = async (dataurl: any) => {
    let arr = dataurl.split(","),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], { type: mime });
}
const handleAvatarSuccess: UploadProps['onSuccess'] = (
    response,
    uploadFile
) => {
}
const uploadAvatorAdd = async (options: UploadRequestOptions) => {
    upload(options.file, 'inch', (res: any) => {
        addForm.inch = res.inch
    },
        (error: any) => {
            console.log(error)
        },
        (percent: any) => {
            console.log(percent)
        }
    )
}
onMounted(() => {
    getRoleList()
    getList()
})
</script>
<style lang="scss" scoped>
.user-info-box {
    width: 100%;
}

.uploadList {
    display: flex;
    flex-flow: wrap;
    width: 100%;
}

:deep(.avatar-uploader .el-upload) {
    width: 72px;
    height: 72px;
    background: #EEEEEE;
    border-radius: 4px;
    border: 1px dashed #DCDCDC;
    font-size: 12px;
    color: rgba(0, 0, 0, 0.4);
    box-sizing: border-box;
    padding: 6px
}

:deep(.el-icon.avatar-uploader-icon) {
    color: #000000;
    margin-bottom: 3px;
    font-size: 14px;
    font-weight: 600;
}

:deep(.avatar-uploader) {
    margin: 0px;
    width: 72px;
}

:deep(.el-input .el-input__wrapper) {
    width: 100% !important;
    box-sizing: border-box !important;
}
</style>